using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.IdentityModel.Logging;
using Microsoft.IdentityModel.Tokens;

namespace Crux.Core.Jwt;
/// <summary>
/// JwtResolver
/// </summary>
public static class JwtResolver
{
    /// <summary>
    /// handler
    /// </summary>
    private static JwtSecurityTokenHandler _handler = new JwtSecurityTokenHandler();
    /// <summary>
    /// 
    /// </summary>
    private static UnauthorizedException UnauthorizedException = new UnauthorizedException("NoPermissionAccess");
    /// <summary>
    /// static .ctor
    /// </summary>
    static JwtResolver()
    {
        IdentityModelEventSource.ShowPII = true;
    }
    /// <summary>
    ///
    /// </summary>
    /// <param name="ticket"></param>
    /// <param name="token"></param>
    /// <param name="securityToken"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentNullException"></exception>
    /// <exception cref="UnauthorizedException"></exception>
    public static ClaimsPrincipal Resolve(
        JwtOption ticket,
        string token,
        out SecurityToken securityToken)
    {
        if (ticket is null)
        {
            throw new ArgumentNullException(nameof(ticket));
        }
        if (string.IsNullOrEmpty(token))
        {
            throw UnauthorizedException;
        }

        var keyBuffer = Encoding.ASCII.GetBytes(ticket.Key);

        try
        {
            var key = new SymmetricSecurityKey(keyBuffer);

            var parameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = key,
                ValidateIssuer = true,
                ValidIssuer = ticket.Issuer,
                ValidateAudience = true,
                ValidAudience = ticket.Audience,
                ValidateLifetime = true,
                ClockSkew = TimeSpan.Zero
            };

            return _handler.ValidateToken(token, parameters, out securityToken);
        }
        catch (Exception e)
        {
            throw e switch
            {
                var x when x is SecurityTokenExpiredException => UnauthorizedException,
                var x when x is SecurityTokenValidationException => UnauthorizedException,
                var x when x is SecurityTokenException => UnauthorizedException,
                var x when x is ArgumentException => UnauthorizedException,
                _ => e
            };
        }
        finally
        {
            Array.Clear(keyBuffer, 0, keyBuffer.Length);
            keyBuffer = null;
        }
    }

}